import Emitter from "@/utils/Emitter";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import MyDRACOLoader from "./MyDRACOLoader";
import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { loadUrl } from "@/utils/Utils";
import { TransformControls } from "three/examples/jsm/controls/TransformControls.js";
import { IMaterial, ITakeMaterial } from "@/interface/common";
import { Box3Controls } from "@/utils/Box3Controls";
import { ViewHelper } from "three/examples/jsm/helpers/ViewHelper.js";
/** 基础模型初始化参数 */
export interface IBaseModelOption {
    /** 渲染器相关属性 */
    renderParams: {
        /** render相关初始化配置 */
        webGLRendererParameters?: THREE.WebGLRendererParameters,
        /** 渲染器的宽 */
        width: number,
        /** 渲染器的高 */
        height: number,
        /** 渲染器的容器 */
        renderContainer: HTMLElement,
        /** 设置设备像素比。通常用于避免HiDPI设备上绘图模糊 */
        devicePixelRatio?: number
    }
    /** 相机相关属性 */
    cameraParams: {
        /** 本基类默认是透视相机，如果需要使用其他相机，就传这个参数 */
        camera?: THREE.Camera,
        /** 摄像机视锥体垂直视野角度 */
        fov: number,
        /** 摄像机视锥体近端面 */
        near: number,
        /** 摄像机视锥体远端面 */
        far: number,
        /** 相机的位置 */
        cameraPosition: THREE.Vector3
    }
    /** 是否需要初始化灯管 */
    isLight?: boolean,
    /** 是否需要轨道控制器 */
    isOrbitControls?: boolean
    /** 是否需要变换控制器 */
    isTransformControls?: boolean
    /** 是否需要视角辅助器 */
    isViewHelper?: boolean
    /** 是否需要平面辅助器 */
    gridHelper?: {
        isGridHelper: boolean,
        size: number,
        divisions: number
    }
}

export class BaseModel extends Emitter {
    renderer !: THREE.WebGLRenderer;
    option !: IBaseModelOption;
    scene !: THREE.Scene;
    orbitControls !: OrbitControls;
    transformControls!: TransformControls;
    /** 控制器上所有可以点击的mesh */
    transformControlsMeshList: THREE.Mesh[] = [];
    camera !: THREE.Camera;
    /** 广场平面 */
    ground !: THREE.Object3D;
    viewHelper !: ViewHelper;
    textureLoader = new THREE.TextureLoader();
    myDRACOLoader = new MyDRACOLoader();
    glftLoader = new GLTFLoader();
    constructor(option: IBaseModelOption) {
        super();
        let initOption: Partial<IBaseModelOption> = {
            isLight: true,
            isOrbitControls: true,
            isTransformControls: false,
            isViewHelper: false,
            gridHelper: {
                size: 20,
                divisions: 20,
                isGridHelper: true
            }
        }
        this.option = {
            ...initOption,
            ...option
        };
    }

    /** 修改集合中材质 */
    static changeGroupMaterial(group: THREE.Object3D, material: (item: THREE.Object3D | ITakeMaterial) => IMaterial | undefined) {
        group?.traverse((item: THREE.Object3D | ITakeMaterial) => {
            if ('material' in item && material(item)) {
                item.material = material(item)!;
            }
        })
    }



    /**  初始化渲染器 */
    initWebGLRenderer() {
        let { renderParams } = this.option;
        let initWebGLRendererParameters: Partial<THREE.WebGLRendererParameters> = {
            antialias: true,
            precision: "lowp", // 解决移动端卡顿问题
            alpha: true,
        }
        //设置渲染器，并添加抗锯齿效果
        this.renderer = new THREE.WebGLRenderer({
            ...initWebGLRendererParameters,
            ...renderParams.webGLRendererParameters
        });
        this.renderer.setPixelRatio(renderParams.devicePixelRatio || window.devicePixelRatio);
        this.renderer.setSize(renderParams.width, renderParams.height)

        renderParams.renderContainer.appendChild(this.renderer.domElement);
    }

    /** 初始化视角指示器 */
    initViewHelper() {
        this.viewHelper = new ViewHelper(this.camera, this.renderer.domElement);
        this.renderer.autoClear = false;
    }

    /**初始化场景 */
    initScene() {
        this.scene = new THREE.Scene();
    }

    /** 初始化相机 */
    initCamera() {
        let { renderParams, cameraParams } = this.option
        if (cameraParams.camera) {
            this.camera = cameraParams.camera;
        } else {
            this.camera = new THREE.PerspectiveCamera(cameraParams.fov, renderParams.width / renderParams.height, cameraParams.near, cameraParams.far);
            this.camera.position.copy(cameraParams.cameraPosition);
        }

    }

    /** 初始化轨道控制器 */
    initOrbitControls() {
        this.orbitControls = new OrbitControls(this.camera, this.renderer.domElement);
    }

    /**  初始化变换控制 */
    initTransformControls() {
        this.transformControls = new TransformControls(this.camera, this.renderer.domElement);
        this.transformControls.traverse((item: any) => {
            // @ts-ignore
            if (item instanceof THREE.Mesh && !item.isTransformControlsPlane) {
                this.transformControlsMeshList.push(item)
            }
        })
        this.scene.add(this.transformControls)
    }

    /** 初始化灯 */
    initLight() {
        const light: THREE.AmbientLight = new THREE.AmbientLight(0xffffff, 0.6);
        this.scene.add(light);
        const pointLight: THREE.PointLight = new THREE.PointLight(0xffffff, 0.5);
        this.scene.add(this.camera);
        this.camera.add(pointLight);
    };

    init() {
        let { isLight, isOrbitControls, isTransformControls, gridHelper, isViewHelper } = this.option;
        this.initScene();
        this.initWebGLRenderer();
        this.initCamera();
        isOrbitControls && this.initOrbitControls();
        isLight && this.initLight();
        isTransformControls && this.initTransformControls();
        gridHelper?.isGridHelper && this.creatGridHelper();
        isViewHelper && this.initViewHelper();
    }

    /** 创建点光源集合 */
    loadPointLightGroup(isNeedHelper: boolean = true, sphereSize: number = 1) {
        const pointLight = new THREE.PointLight(0xffffff, 1, 100);
        const group = new THREE.Group();
        if (isNeedHelper) {
            const pointLightHelper = new THREE.PointLightHelper(pointLight, sphereSize);
            pointLightHelper.matrixAutoUpdate = true;
            group.add(pointLightHelper);
        }
        group.add(pointLight);
        return group
    }

    /** 创建聚光灯集合 */
    loadSpotLightGroup(isNeedHelper: boolean = true, sphereSize: number = 1) {
        const spotLight = new THREE.SpotLight(0x00ff00, 4, 4, Math.PI / 9,);
        const group = new THREE.Group();
        if (isNeedHelper) {
            const spotLightHelper = new THREE.SpotLightHelper(spotLight, sphereSize);
            spotLightHelper.matrixAutoUpdate = true;
            group.add(spotLightHelper);
        }
        group.add(spotLight);
        return group
    }

    /** 加载glb模型 */
    loadGlbModel(url: string) {
        return new Promise(async (resolve: (value: GLTF) => void, reject) => {
            this.glftLoader.setDRACOLoader(this.myDRACOLoader.getDRACOLoader());
            this.glftLoader.load(url, (gltf: GLTF) => {
                resolve(gltf)
            }, (xhr) => { }, (error) => {
                reject(error)
            })
        })
    }

    /** 加载贴图 */
    loadTextureMap(url: string) {
        return new Promise(async (resolve: (value: THREE.Texture) => void, reject) => {
            this.textureLoader.load(url, (texture: THREE.Texture) => {
                resolve(texture)
            }, undefined, (error) => {
                reject(error)
            })
        })
    }

    /** 创建包围盒并新建group将点位挪到需要物体的中心 */
    creatBox3AndToGroupCenter(mesh: THREE.Group, box3Name: string, groupName: string) {
        let group = new THREE.Group();
        group.name = groupName;
        group.add(mesh);
        let box3Controls = new Box3Controls({
            mesh: group,
            box3Name: box3Name
        });
        return {
            group,
            box3Controls
        };
    }

    /** 创建平面辅助器 */
    creatGridHelper() {
        if (!this.option.gridHelper) return;
        let { size, divisions } = this.option.gridHelper;
        const helper = new THREE.GridHelper(size, divisions);
        helper.material.opacity = 0.25;
        helper.material.transparent = true;
        this.ground = helper
        this.scene.add(helper);
    }

    /** 销毁group*/
    disposeGroup(group: THREE.Group) {
        // 递归遍历组对象group释放所有后代网格模型绑定几何体占用内存
        group.traverse((item: THREE.Object3D) => {
            if (item instanceof THREE.Mesh) {
                item.geometry.dispose();
                item.material.dispose();
            }
        });
        // 删除场景对象scene的子对象group
        this.scene.remove(group);
    }

    updata() {
        const { isViewHelper } = this.option
        this.renderer?.render(this.scene, this.camera);
        isViewHelper && this.viewHelper.render(this.renderer)
    }


}
